home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / net / omniORB-2.5.0-src.tar.gz / omniORB-2.5.0-src.tar / omniORB_2.5.0 / include / omniORB2 / rope.h < prev    next >
C/C++ Source or Header  |  1997-12-09  |  30KB  |  869 lines

  1. // -*- Mode: C++; -*-
  2. //                            Package   : omniORB2
  3. // rope.h                     Created on: 6/2/96
  4. //                            Author    : Sai Lai Lo (sll)
  5. //
  6. //    Copyright (C) 1996, 1997 Olivetti & Oracle Research Laboratory
  7. //
  8. //    This file is part of the omniORB library
  9. //
  10. //    The omniORB library is free software; you can redistribute it and/or
  11. //    modify it under the terms of the GNU Library General Public
  12. //    License as published by the Free Software Foundation; either
  13. //    version 2 of the License, or (at your option) any later version.
  14. //
  15. //    This library is distributed in the hope that it will be useful,
  16. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18. //    Library General Public License for more details.
  19. //
  20. //    You should have received a copy of the GNU Library General Public
  21. //    License along with this library; if not, write to the Free
  22. //    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
  23. //    02111-1307, USA
  24. //
  25. //
  26. // Description:
  27. //    *** PROPRIETORY INTERFACE ***
  28. //    
  29.  
  30. /*
  31.   $Log: rope.h,v $
  32.   Revision 1.4  1997/12/09 20:34:36  sll
  33.   Interfaces extended to provide more hooks to support new transports.
  34.   Support for incoming and outgoing rope scavenger threads.
  35.  
  36.  * Revision 1.3  1997/05/06  16:10:38  sll
  37.  * Public release.
  38.  *
  39.   */
  40.  
  41. #ifndef __ROPE_H__
  42. #define __ROPE_H__
  43.  
  44. // A Rope is a bi-directional buffered stream connecting two address
  45. // spaces. The connection point of each address space can be identified by
  46. // an Endpoint. A Rope may be composed of one or more Strands. Each Strand
  47. // represents a transport dependent connection. All strands of the same
  48. // rope can be used interchangable for sending and receiving messages
  49. // between the connected address spaces.
  50.  
  51. // Built on top of a strand, the GIOP_C and GIOP_S classes are defined to
  52. // drive the General Inter-ORB Protocol (GIOP). The GIOP protocol
  53. // is asymmetric.  GIOP_C provides the functions to drive the client side
  54. // protocol.  GIOP_S provides the server side functions.
  55.  
  56. class Rope;
  57. class Endpoint;
  58. class NetBufferedStream;
  59. class Strand_iterator;
  60. class Rope_iterator;
  61.  
  62. class Strand {
  63. public:
  64.  
  65.   Strand(Rope *r,_CORBA_Boolean heapAllocated = 0);
  66.   // Concurrency Control:
  67.   //    MUTEX = r->pd_lock
  68.   // Pre-condition:
  69.   //    Must hold <MUTEX> on entry
  70.   // Post-condition:
  71.   //    Still hold <MUTEX> on exit, even if an exception is raised
  72.  
  73.   virtual ~Strand();
  74.   // Concurrency Control:
  75.   //    MUTEX = pd_rope->pd_lock
  76.   // Pre-condition:
  77.   //    Must hold <MUTEX> on entry
  78.   // Post-condition:
  79.   //    Still hold <MUTEX> on exit
  80.  
  81.   virtual size_t MaxMTU() const = 0;
  82.   // Maximum message transfer unit. This value is transport dependent.
  83.  
  84.   struct sbuf {
  85.     void  *buffer;
  86.     size_t size;
  87.   };
  88.  
  89.   virtual sbuf receive(size_t size,_CORBA_Boolean exactly,
  90.                int align,_CORBA_Boolean startMTU=0)=0;
  91.   // Concurrency Control:
  92.   //      RdLock()
  93.   // Pre-condition:
  94.   //      Must hold RdLock()
  95.   // Post-condition:
  96.   //      Still hold RdLock()
  97.   //
  98.   // If <exactly> is true, receive exactly <size> bytes from this strand
  99.   // before returning. If <exactly> is false, receive at most <size> bytes
  100.   // from this strand. If <exactly> is true, the value of <size> cannot be
  101.   // larger than the return value of max_receive_buffer_size().
  102.   //
  103.   // If startMTU is TRUE (1), the caller expects what is coming in to be
  104.   // the start of a request message. If the strand detects that is not the
  105.   // case, it should shutdown itself and throw a COMM_FAILURE exception.
  106.   //
  107.   // The return structure <sbuf> contains a pointer to the data area and
  108.   // the number of bytes actually received. The data pointer is guaranteed to
  109.   // be aligned to the boundary specified in <align>.
  110.   //
  111.   // This strand retains ownership of the data buffer.
  112.   // The data area contains the received data *until* the next call to 
  113.   // receive() or giveback_received(). That is, the next receive() or
  114.   // giveback_received() call automatically invalidates the
  115.   // data pointer returned by this call.
  116.   //
  117.   // ******* To service this call, the strand may or may not need to 
  118.   //         fetch more data from the network. For instance, it may be
  119.   //         able to provide the data from its internal buffer.
  120.   //
  121.   // This function *should be* called only after the current thread has 
  122.   // acquired the read lock of this strand. The thread should not relinquish 
  123.   // the read lock until it has consumed all the data it gets from this 
  124.   // function or has copied out the data.
  125.  
  126.  
  127.   virtual void giveback_received(size_t leftover)=0;
  128.   // Concurrency Control:
  129.   //      RdLock()
  130.   // Pre-condition:
  131.   //      Must hold RdLock()
  132.   // Post-condition:
  133.   //      Still hold RdLock()
  134.   //
  135.   // This function gives back to the strand <leftover> bytes at the
  136.   // end of the data area given out by the previous receive() call.
  137.   // The value of <leftover> must be less than or equal to the size of
  138.   // the received data.
  139.   // This function *should be* called only after the current thread has
  140.   // acquired the read lock of this strand.
  141.   
  142.   virtual size_t max_receive_buffer_size()=0;
  143.   // Concurrency Control:
  144.   //      None required.
  145.   // The maximum size of the data area that can be returned by receive()
  146.  
  147.   virtual void receive_and_copy(sbuf b,_CORBA_Boolean startMTU=0) = 0;
  148.   // Concurrency Control:
  149.   //      RdLock()
  150.   // Pre-condition:
  151.   //      Must hold RdLock()
  152.   // Post-condition:
  153.   //      Still hold RdLock()
  154.   //
  155.   // Copying incoming data directly to the buffer points to by <b>.
  156.   // Exactly <b.size> bytes are copied before returning.
  157.   //
  158.   // If startMTU is TRUE (1), the caller expects what is coming in to be
  159.   // the start of a request message. If the strand detects that is not the
  160.   // case, it should shutdown itself and throw a COMM_FAILURE exception.
  161.   //
  162.   // The semantics of this function is equivalent to a receive() followed by
  163.   // a memcpy().
  164.   //
  165.   // This function may be used instead of receive() for bulk data,
  166.   // such as a long sequence of Octets. The function allows for optimisation
  167.   // within the strand to directly copy the data from network buffers to the
  168.   // designated data area.
  169.   // This function *should be* called only after the current thread has
  170.   // acquired the read lock of this strand.
  171.  
  172.   virtual void skip(size_t size,_CORBA_Boolean startMTU=0) = 0;
  173.   // Concurrency Control:
  174.   //      RdLock()
  175.   // Pre-condition:
  176.   //      Must hold RdLock()
  177.   // Post-condition:
  178.   //      Still hold RdLock()
  179.   //
  180.   // Drop <size> bytes of incoming data from this strand before returning.
  181.   // The semantics of this call is equivalent to one or more receive() 
  182.   // calls until <size> bytes are "received".
  183.   // This function *should be* called only after the current thread has
  184.   // acquired the read lock of this strand.
  185.   //
  186.   // If startMTU is TRUE (1), the caller expects what is coming in to be
  187.   // the start of a request message. If the strand detects that is not the
  188.   // case, it should shutdown itself and throw a COMM_FAILURE exception.
  189.  
  190.   virtual sbuf reserve(size_t size,_CORBA_Boolean exactly,int align,
  191.                _CORBA_Boolean transmit=0,_CORBA_Boolean endMTU=0)=0;
  192.   // Concurrencty Control:
  193.   //       WrLock()
  194.   // Pre-condition:
  195.   //       Must hold WrLock()
  196.   // Post-condition
  197.   //       Still hold WrLock()
  198.   //
  199.   // if <exactly> is true, reserve exactly <size> bytes from the output
  200.   // buffer of this strand. If <exactly> is false, reserve at most <size>
  201.   // bytes from this strand. If <exactly> is true, the value of <size> cannot
  202.   // be larger than the return value of max_reserve_buffer_size();
  203.   //
  204.   // If endMTU is TRUE(1), the caller indicates that it is reserving buffer
  205.   // to write the last part of a request message.
  206.   //
  207.   //
  208.   // The return structure <sbuf> contains a pointer to the data area and
  209.   // the number of bytes actually reserved. The data pointer is guaranteed to
  210.   // be aligned to the boundary specified in <align>.
  211.   //
  212.   // This strand retains the ownership of the data buffer.
  213.   //
  214.   // The caller can write to this data area *until* the next call to reserve()
  215.   // or giveback_reserved(). In other words, the caller can use either of 
  216.   // the functions to instruct the strand that all or part of the data area 
  217.   // is now filled up with valid data. If <transmit> is true, any buffered data
  218.   // will be transmitted immediately. If <transmit> is false, any buffered
  219.   // data may be transmitted any time hereafter.
  220.   //
  221.   // This function *should be* called only after the current thread has
  222.   // acquired the write lock of this strand.
  223.  
  224.   virtual sbuf reserve_and_startMTU(size_t size,_CORBA_Boolean exactly,
  225.                     int align,_CORBA_Boolean transmit=0,
  226.                     _CORBA_Boolean at_most_once=0)=0;
  227.   // The function is the same as reserve() except that it is used by
  228.   // the caller to indicate that it is reserving buffer to write the beginning
  229.   // of a request message.
  230.  
  231.   virtual void giveback_reserved(size_t leftover,_CORBA_Boolean transmit=0,
  232.                  _CORBA_Boolean endMTU=0)=0;
  233.   // Concurrencty Control:
  234.   //       WrLock()
  235.   // Pre-condition:
  236.   //       Must hold WrLock()
  237.   // Post-condition
  238.   //       Still hold WrLock()
  239.   //
  240.   // This function gives back to the strand <leftover> bytes of space at
  241.   // the end of the data area reserved by the previous reserve() call. The
  242.   // strand would consider this area unfilled and would not transmit its
  243.   // content. Any part of the data area not returned by this call are taken
  244.   // as filled with valid data. If <transmit> is true, any buffered data
  245.   // will be transmitted immediately. If <transmit> is false, any buffered
  246.   // data may be transmitted any time hereafter.
  247.   //
  248.   // The value of <leftover> must be less than or equal to the size of the 
  249.   // data area reserved.
  250.   //
  251.   // If endMTU is TRUE(1), the caller indicates that it has written
  252.   // the last part of a request message.
  253.   //
  254.   // This function *should be* called only after the current thread has
  255.   // acquired the write lock of this strand.
  256.  
  257.   virtual size_t max_reserve_buffer_size() = 0;
  258.   // Concurrency Control:
  259.   //       None required
  260.   // The maximum size of the data area that can be returned by reserve()
  261.  
  262.   virtual void reserve_and_copy(sbuf b,_CORBA_Boolean transmit=0,
  263.                 _CORBA_Boolean endMTU=0) = 0;
  264.   // Concurrency Control:
  265.   //       WrLock()
  266.   // Pre-condition:
  267.   //       Must hold WrLock()
  268.   // Post-condition
  269.   //       Still hold WrLock()
  270.   //
  271.   // Transmit data from the buffer points to by <b>. The semantics of this
  272.   // function is equivalent to one or more calls to reserve() and memcpy().
  273.   //
  274.   // This function may be used instead of reserve() for bulk data,
  275.   // such as a long sequence of Octets. The function allows for optimisation
  276.   // within the strand to directly copy the data to network buffers.
  277.   // If <transmit> is true, any buffered data will be transmitted immediately. 
  278.   // If <transmit> is false, any buffered data may be transmitted any time 
  279.   // hereafter.
  280.   //
  281.   // If endMTU is TRUE(1), the caller indicates that it is reserving buffer
  282.   // to write the last part of a request message.
  283.   //
  284.   // This function *should be* called only after the current thread has
  285.   // acquired the write lock of this strand.
  286.  
  287.   _CORBA_ULong sequenceNumber() { return pd_seqNumber++; }
  288.   // Concurrency Control:
  289.   //       WrLock()
  290.   // Pre-condition:
  291.   //       Must hold WrLock()
  292.   // Post-condition
  293.   //       Still hold WrLock()
  294.   //
  295.   // The integer returned by this function is guaranteed to be different
  296.   // from those returned in previous calls. A client may use this number
  297.   // to tag the messages sent via a strand.
  298.  
  299.   virtual void shutdown() = 0;
  300.   // Concurrency Control:
  301.   //    MUTEX = pd_rope->pd_lock
  302.   // Pre-condition:
  303.   //    Must hold <MUTEX> on entry
  304.   // Post-condition:
  305.   //    Still hold <MUTEX> on exit
  306.   //
  307.   // Signal to any thread currently using this strand to give up because
  308.   // this strand is being shut down.
  309.   // Never returns an exception and never blocks
  310.  
  311.   void incrRefCount(_CORBA_Boolean held_rope_mutex = 0);
  312.   // Concurrency Control:
  313.   //      MUTEX = pd_rope->pd_lock
  314.   // Pre-condition:
  315.   //      Does not hold <MUTEX> on enter if held_rope_mutex == FALSE
  316.   //      Hold <MUTEX> on enter if held_rope_mutex == TRUE              
  317.   // Post-condition:
  318.   //      Restore <MUTEX> to the same state as indicated by held_rope_mutex
  319.  
  320.   void decrRefCount(_CORBA_Boolean held_rope_mutex = 0);
  321.   // Concurrency Control:
  322.   //      MUTEX = pd_rope->pd_lock
  323.   // Pre-condition:
  324.   //      Does not hold <MUTEX> on enter if held_rope_mutex == FALSE
  325.   //      Hold <MUTEX> on enter if held_rope_mutex == TRUE              
  326.   // Post-condition:
  327.   //      Restore <MUTEX> to the same state as indicated by held_rope_mutex
  328.  
  329.   _CORBA_Boolean is_idle(_CORBA_Boolean held_rope_mutex = 0);
  330.   // Concurrency Control:
  331.   //      MUTEX = pd_rope->pd_lock
  332.   // Pre-condition:
  333.   //      Does not hold <MUTEX> on enter if held_rope_mutex == FALSE
  334.   //      Hold <MUTEX> on enter if held_rope_mutex == TRUE              
  335.   // Post-condition:
  336.   //      Restore <MUTEX> to the same state as indicated by held_rope_mutex
  337.  
  338.  
  339.   class Sync {
  340.  
  341.   public:
  342.     Sync(Strand *s,_CORBA_Boolean RdLock=1,_CORBA_Boolean WrLock=1);
  343.     // Concurrency Control:
  344.     //    MUTEX = s->pd_rope->pd_lock
  345.     // Pre-condition:
  346.     //    Does not hold <MUTEX> on entry
  347.     // Post-condition:
  348.     //    Does not hold <MUTEX> on exit, even if an exception is raised.
  349.     //
  350.     // Exclusive access to a Strand is provided by instantiating a Sync
  351.     // object. Initial locking modes can be specified in the constructor
  352.     // of the Sync object. The constructor also enters the Sync object
  353.     // to a private queue of the Strand. The iterator Sync_iterator can
  354.     // be used to go through all the Sync objects that are associated with
  355.     // a Strand.
  356.     //
  357.     // Caller must ensure that the reference count of the argument strand <s>
  358.     // is non-zero. This ctor also increment the reference count of the
  359.     // strand internally using Strand::incrRefCount().
  360.  
  361.     Sync(Rope *r,_CORBA_Boolean RdLock=1,_CORBA_Boolean WrLock=1);
  362.     // Concurrency Control:
  363.     //    MUTEX = r->pd_lock
  364.     // Pre-condition:
  365.     //      Does not hold <MUTEX> on entry
  366.     // Post-condition:
  367.     //      Does not hold <MUTEX> on exit, even if an exception is raised.
  368.     //
  369.     // A strand from the argument <r> is grabbed by this Sync object.
  370.     // This ctor also increment the reference count of the strand internally
  371.     // using Strand::incrRefCount().
  372.  
  373.     ~Sync();
  374.     // Concurrency Control:
  375.     //       MUTEX = pd_strand->pd_rope->pd_lock
  376.     // Pre-condition:
  377.     //    Does not hold <MUTEX> on entry
  378.     // Post-condition:
  379.     //    Does not hold <MUTEX> on exit
  380.     //    
  381.     // IMPORTANT: the destructor DOES NOT check whether a read or a write
  382.     //            lock is held by this object. Make sure that any lock
  383.     //            is released, using RdUnlock() and WrUnlock(), before this
  384.     //            destructor is called.
  385.     //
  386.     // This dtor decrement the reference count of the strand by calling
  387.     // Strand::decrRefCount(). If the reference count reaches 0 
  388.     // (Strand::is_idle() returns TRUE) and the strand has been flagged for
  389.     // closing down (Strand::StrandIsDying() returns TRUE), the dtor of the
  390.     // strand is called.
  391.  
  392.     _CORBA_Boolean isReUsingExistingConnection() const;
  393.     // Concurency Control:
  394.     //     None required.
  395.     //
  396.     // Returns true if this is not the first Sync object instantiated to
  397.     // use the Strand. False otherwise.
  398.     // This method is intended for the caller to decide on a course of
  399.     // action if a COMM_FAILURE has been thrown. If this method returns
  400.     // true, the COMM_FAILURE may be considered a soft failure because
  401.     // it is only a cached network connection that is broken. If this method
  402.     // returns false, then the connection to the remote end is really
  403.     // broken and may be considered as a hard failure.
  404.  
  405.  
  406.     static _CORBA_Boolean WrTimedLock(Strand* s,
  407.                       _CORBA_Boolean& heartbeat,
  408.                       unsigned long secs,
  409.                       unsigned long nanosecs);
  410.     static void WrUnlock(Strand* s);
  411.   protected:
  412.     void RdLock(_CORBA_Boolean held_rope_mutex=0);
  413.     void WrLock(_CORBA_Boolean held_rope_mutex=0,
  414.         _CORBA_Boolean clear_heartbeat=1);
  415.     void RdUnlock(_CORBA_Boolean held_rope_mutex=0);
  416.     void WrUnlock(_CORBA_Boolean held_rope_mutex=0);
  417.     // IMPORTANT: to avoid deadlock, the following protocol MUST BE obeyed.
  418.     //            1. Acquire Read lock before Write Lock.
  419.     //            2. Never acquire a Read lock while holding a Write lock.
  420.     //               Must release the Read lock first.
  421.     // Concurrency Control:
  422.     //       MUTEX = pd_strand->pd_rope->pd_lock or argument <s>->pd_rope->pd_lock
  423.     // Pre-condition:
  424.     //      For RdLock(), WrLock(), RdUnlock(), WrUnlock():
  425.     //          Does not hold <MUTEX> on enter if held_rope_mutex == FALSE
  426.     //          Hold <MUTEX> on enter if held_rope_mutex == TRUE
  427.     //      For WrTimedLock(), WrUnlock(Strand*):
  428.     //          Must hold <MUTEX> on enter
  429.     // Post-condition:
  430.     //      For RdLock(), WrLock(), RdUnlock(), WrUnlock():
  431.     //        Restore <MUTEX> to the same state as indicated by held_rope_mutex
  432.     //      For WrTimedLock(), WrUnlock(Strand*):
  433.     //        Still held <MUTEX> on exit
  434.     //
  435.     // There are two ways to acquire a Write Lock, 
  436.     //    i.e. WrLock and WrTimedLock.
  437.     //
  438.     // WrLock blocks until it has acquired a write lock on the strand.
  439.     // WrTimedLock tries to acquire a write lock on the strand until the
  440.     // current time is later than the absolute time given in the arguments
  441.     // <secs> and <nanosecs>. These time arguments are interpreted in the
  442.     // same way as omni_condition::timedwait(). If WrTimedLock returns 1,
  443.     // the write lock has been acquired, otherwise it has timeout and no
  444.     // lock has been acquired.
  445.     //
  446.     // A strand has a status boolean known as the 'heartbeat', this boolean
  447.     // value may be set/unset and read as a side-effect of WrLock and 
  448.     // WrTimeLock. The initial value of the boolean is 0.
  449.     //
  450.     // If <clear_heartbeat> is 1 (the default), WrLock will set the heartbeat
  451.     // boolean to 0 after it has acquired the write lock. If <clear_heartbeat>
  452.     // is 0, WrLock will leave the heartbeat boolean unchanged.
  453.     // 
  454.     // The heartbeat boolean will be updated by WrTimedLock with the value
  455.     // of <heartbeat> after it has acquired the write lock. The original value
  456.     // of the boolean is returned in <heartbeat>.
  457.     //
  458.     // The value of the heartbeat boolean *does not* affect the internal
  459.     // functions of the strand. However, it is used as a way to detect
  460.     // whether a strand is idle and can be closed down. The algorithm is as
  461.     // follows:
  462.     //      A scavenger thread periodically scans all the strands. It acquires
  463.     //      the write lock on the strand using WrTimedLock. It sets the
  464.     //      heartbeat boolean to 1 and examines the original value returned by 
  465.     //      WrTimedLock. If the original value is also 1, it knows the strand 
  466.     //      has been idle for at least one scan period. It may then shutdown
  467.     //      the strand.
  468.     // 
  469.     //      To prevent a strand from being shutdown, the thread that uses
  470.     //      the strand must reset the heartbeat boolean to 0 at least once
  471.     //      within the scan period. This can be done conveniently as a 
  472.     //      side-effect of WrLock, i.e. with the <clear_heartbeat> = 1. 
  473.     //      Typically, a thread acquires a write lock on the strand
  474.     //      when it is about to send a reply (on the server side) or a request
  475.     //      (on the client side). This is a good indication that the strand
  476.     //      is in active use.
  477.  
  478.     Strand *get_strand() { return pd_strand; }
  479.     // Concurrency Control:
  480.     //     None required.
  481.  
  482.     void setStrandIsDying();
  483.     // Concurrency Control:
  484.     //     None. Beware of race conditions!!!
  485.     // Same as Strand::_setStrandIsDying
  486.  
  487.     _CORBA_Boolean strandIsDying();
  488.     // Concurrency Control:
  489.     //     None. Beware of race conditions!!!!
  490.     // Same as Strand::_strandIsDying.
  491.     
  492.   private:
  493.     Sync *pd_next;
  494.     Strand *pd_strand;
  495.     _CORBA_Boolean pd_secondHand;
  496.     Sync();
  497.   };
  498.  
  499.   _CORBA_Boolean _strandIsDying() { return pd_dying; }
  500.  
  501. protected:
  502.  
  503.   void _setStrandIsDying() { pd_dying = 1; return; }
  504.  
  505.   friend class Sync;
  506.   friend class Strand_iterator;
  507.   friend class Rope;
  508.   friend class Rope_iterator;
  509.  
  510. private:
  511.   omni_condition  pd_rdcond;
  512.   int             pd_rd_nwaiting;
  513.  
  514.   omni_condition  pd_wrcond;
  515.   int             pd_wr_nwaiting;
  516.  
  517.   Sync           *pd_head;
  518.   Strand         *pd_next;
  519.   Rope           *pd_rope;
  520.   _CORBA_Boolean  pd_dying;
  521.   _CORBA_Boolean  pd_heapAllocated;
  522.   _CORBA_Boolean  pd_heartbeat;
  523.   int          pd_refcount;
  524.   _CORBA_ULong     pd_seqNumber;
  525.  
  526.   // Make the default constructor private. This traps at compile time
  527.   // any attempt to allocate an array of objects using the new operator.
  528.   Strand();
  529.   Strand(const Strand&);
  530.   Strand &operator=(const Strand&);
  531. };
  532.  
  533. typedef Strand::Sync Strand_Sync;
  534.  
  535. class Endpoint {
  536. public:
  537.   Endpoint(_CORBA_Char *protocol) {
  538.     pd_protocolname = new _CORBA_Char [strlen((char *)protocol)+1];
  539.     strcpy((char *)pd_protocolname,(char *)protocol);
  540.     return;
  541.   }
  542.  
  543.   Endpoint(const Endpoint &e) {
  544.     pd_protocolname = new _CORBA_Char [strlen((char *)e.pd_protocolname)+1];
  545.     strcpy((char *)pd_protocolname,(char *)e.pd_protocolname);
  546.     return;
  547.   }
  548.  
  549.   Endpoint &operator=(const Endpoint &e) {
  550.     delete [] pd_protocolname;
  551.     pd_protocolname = new _CORBA_Char [strlen((char *)e.pd_protocolname)+1];
  552.     strcpy((char *)pd_protocolname,(char *)e.pd_protocolname);
  553.     return *this;
  554.   }
  555.  
  556.   virtual ~Endpoint() {
  557.     delete [] pd_protocolname;
  558.     return;
  559.   }
  560.  
  561.   _CORBA_Boolean is_protocol(const _CORBA_Char *name) const {
  562.     if (strcmp((const char *)name,(char *)pd_protocolname) == 0) {
  563.       return 1;
  564.     }
  565.     else {
  566.       return 0;
  567.     }
  568.   }
  569.  
  570.   _CORBA_Char* protocol() const {
  571.     return pd_protocolname;
  572.   }
  573.  
  574. private:
  575.   _CORBA_Char * pd_protocolname;
  576.   Endpoint();
  577. };
  578.  
  579. class Endpoint_var {
  580. public:
  581.   Endpoint_var() : pd_p(0) {}
  582.   Endpoint_var(Endpoint* p) : pd_p(p) {}
  583.   ~Endpoint_var() { if (pd_p) delete pd_p; }
  584.   Endpoint_var& operator=(Endpoint* p) {
  585.     if (pd_p) delete pd_p;
  586.     pd_p = p;
  587.     return *this;
  588.   }
  589.   operator Endpoint*() const { return pd_p; }
  590. private:
  591.   Endpoint* pd_p;
  592.   Endpoint_var& operator=(const Endpoint_var&);
  593. };
  594.  
  595. class Strand_iterator {
  596. public:
  597.   Strand_iterator(const Rope *r,_CORBA_Boolean held_rope_mutex = 0);
  598.   // Concurrency Control:
  599.   //      MUTEX = r->pd_lock
  600.   // Pre-condition:
  601.   //      Does not hold <MUTEX> on enter if held_rope_mutex == FALSE
  602.   //      Hold <MUTEX> on enter if held_rope_mutex == TRUE              
  603.   // Post-condition:
  604.   //      Hold <MUTEX> on exit
  605.  
  606.   ~Strand_iterator();
  607.   // Concurrency Control:
  608.   //      MUTEX = pd_rope->pd_lock
  609.   // Pre-condition:
  610.   //      Hold <MUTEX> on enter
  611.   // Post-condition:
  612.   //      Does not hold <MUTEX> on exit if pd_leave_mutex == FALSE
  613.   //      Hold <MUTEX> on exit if pd_leave_mutex == TRUE
  614.  
  615.   Strand *operator() ();
  616.  
  617. private:
  618.   const Rope   *pd_rope;
  619.   _CORBA_Boolean pd_leave_mutex;
  620.   Strand *pd_s;
  621.   Strand_iterator();
  622. };
  623.  
  624. class Anchor {
  625. public:
  626.   Anchor();
  627.   ~Anchor();
  628.  
  629. private:
  630.   friend class Rope;
  631.   friend class Rope_iterator;
  632.  
  633.   omni_mutex   pd_lock;
  634.   Rope        *pd_head;
  635. };
  636.  
  637.  
  638.  
  639. class Rope {
  640. public:
  641.   Rope(Anchor *a,
  642.        unsigned int maxStrands,
  643.        _CORBA_Boolean heapAllocated = 0);
  644.   // Concurrency Control:
  645.   //    MUTEX = a->pd_lock
  646.   // Pre-condition:
  647.   //    Must hold <MUTEX> on entry
  648.   // Post-condition:
  649.   //    Still hold <MUTEX> on exit, even if an exception is raised
  650.  
  651.   virtual ~Rope();
  652.   // Concurrency Control:
  653.   //    MUTEX = pd_anchor->pd_lock
  654.   // Pre-condition:
  655.   //    Must hold <MUTEX> on entry
  656.   // Post-condition:
  657.   //    Still hold <MUTEX> on exit
  658.  
  659.   virtual void CutStrands(_CORBA_Boolean held_rope_mutex = 0);
  660.   // Concurrency Control:
  661.   //      MUTEX = pd_lock
  662.   // Pre-condition:
  663.   //      Does not hold <MUTEX> on enter if held_rope_mutex == FALSE
  664.   //      Hold <MUTEX> on enter if held_rope_mutex == TRUE              
  665.   // Post-condition:
  666.   //      Restore <MUTEX> to the same state as indicated by held_rope_mutex
  667.  
  668.   virtual _CORBA_Boolean is_incoming() const = 0;
  669.   // Return TRUE (1) if this is an incoming rope;
  670.   // Concurrency Control:
  671.   //      None required.
  672.  
  673.   virtual _CORBA_Boolean is_outgoing() const = 0;
  674.   // Return TRUE (1) if this is an outgoing rope;
  675.   // Concurrency Control:
  676.   //      None required.
  677.  
  678.   virtual _CORBA_Boolean remote_is(Endpoint *&e) = 0;
  679.   // Returns FALSE if this is not an outgoing rope.
  680.   // If e == 0, returns the remote endpoint in e and returns TRUE
  681.   // else compare e with the remote endpoint and returns TRUE if they are the
  682.   // same.
  683.   // Concurrency Control:
  684.   //      None required.
  685.  
  686.   virtual _CORBA_Boolean this_is(Endpoint *&e) = 0;
  687.   // Returns FALSE if this is not an incoming rope
  688.   // If e == 0, returns this endpoint in e and returns TRUE
  689.   // else compare e with this endpoint and returns TRUE if they are the same.
  690.   // Concurrency Control:
  691.   //      None required.
  692.  
  693.   void incrRefCount(_CORBA_Boolean held_anchor_mutex = 0);
  694.   // Concurrency Control:
  695.   //      MUTEX = pd_anchor->pd_lock
  696.   // Pre-condition:
  697.   //      Does not hold <MUTEX> on enter if held_anchor_mutex == FALSE
  698.   //      Hold <MUTEX> on enter if held_anchor_mutex == TRUE              
  699.   // Post-condition:
  700.   //      Restore <MUTEX> to the same state as indicated by held_anchor_mutex
  701.  
  702.   void decrRefCount(_CORBA_Boolean held_anchor_mutex = 0);
  703.   // Concurrency Control:
  704.   //      MUTEX = pd_anchor->pd_lock
  705.   // Pre-condition:
  706.   //      Does not hold <MUTEX> on enter if held_anchor_mutex == FALSE
  707.   //      Hold <MUTEX> on enter if held_anchor_mutex == TRUE              
  708.   // Post-condition:
  709.   //      Restore <MUTEX> to the same state as indicated by held_anchor_mutex
  710.  
  711.   _CORBA_Boolean is_idle(_CORBA_Boolean held_anchor_mutex = 0);
  712.   // Concurrency Control:
  713.   //      MUTEX = pd_anchor->pd_lock
  714.   // Pre-condition:
  715.   //      Does not hold <MUTEX> on enter if held_anchor_mutex == FALSE
  716.   //      Hold <MUTEX> on enter if held_anchor_mutex == TRUE              
  717.   // Post-condition:
  718.   //      Restore <MUTEX> to the same state as indicated by held_anchor_mutex
  719.  
  720.  
  721.   Anchor* anchor() const { return pd_anchor; }
  722.  
  723.   friend class Strand;
  724.   friend class Strand_iterator;
  725.   friend class Rope_iterator;
  726.  
  727. #ifndef __DECCXX
  728.   // DEC C++ compiler (as of version 5.4) fails to recognise class Strand::Sync
  729.   // is a friend and allows access to the following protected members.
  730.  
  731.   friend class Strand::Sync;
  732.  
  733. protected:
  734.  
  735. #endif
  736.  
  737.   omni_mutex pd_lock;
  738.   virtual Strand *getStrand(_CORBA_Boolean& secondHand);
  739.   // Concurrency Control:
  740.   //     MUTEX = pd_lock
  741.   // Pre-condition:
  742.   //     Must hold <MUTEX> on entry
  743.   // Post-condition:
  744.   //     Must hold <MUTEX> on exit, even if an exception is raised
  745.   //
  746.   // getStrand() returns a ptr to an unused Strand, i.e. there is no
  747.   // Strand::Sync object associated with it. If none is available and
  748.   // the number of strands has not exceeded pd_maxStrands, call newStrand()
  749.   // to create a new one.
  750.   // A thread may be blocked in this function until a free strand is available.
  751.   //
  752.   // Strands created as a side-effect of this call may be cached to serve
  753.   // subsequent calls. If the strand is created directly as a result of
  754.   // this call, i.e.  no request has gone through yet, <secondHand> is set
  755.   // to 0. Otherwise, this is a cached strand, <secondHand> is set to 1.
  756.   //
  757.  
  758.   virtual Strand *newStrand() = 0;
  759.   // Concurrency Control:
  760.   //     MUTEX = pd_lock
  761.   // Pre-condition:
  762.   //     Must hold <MUTEX> on entry
  763.   // Post-condition:
  764.   //     Must hold <MUTEX> on exit, even if an exception is raised
  765.  
  766. private:
  767.  
  768.  
  769.   unsigned int    pd_maxStrands;
  770.  
  771.   _CORBA_Boolean  pd_heapAllocated;
  772.  
  773.   Strand         *pd_head;
  774.   Rope           *pd_next;
  775.   Anchor          *pd_anchor;
  776.   int              pd_refcount;
  777.  
  778.   Rope();
  779. };
  780.  
  781. class Rope_var {
  782. public:
  783.   inline Rope_var() : _ptr(0) {}
  784.  
  785.   inline Rope_var(Rope* p) { _ptr = p; }
  786.  
  787.   inline ~Rope_var() {
  788.     if (_ptr)
  789.       _ptr->decrRefCount();
  790.   }
  791.  
  792.   inline Rope_var(const Rope_var& p) {
  793.     if (_ptr) {
  794.       _ptr->decrRefCount();
  795.       _ptr = 0;
  796.     }
  797.     if (p._ptr) {
  798.       p._ptr->incrRefCount();
  799.     }
  800.     _ptr = p._ptr;
  801.   }
  802.  
  803.   inline Rope_var& operator= (const Rope_var& p) {
  804.     if (_ptr) {
  805.       _ptr->decrRefCount();
  806.       _ptr = 0;
  807.     }
  808.     if (p._ptr) {
  809.       p._ptr->incrRefCount();
  810.     }
  811.     _ptr = p._ptr;
  812.     return *this;
  813.   }
  814.  
  815.   inline Rope_var& operator= (Rope* p) {
  816.     if (_ptr) {
  817.       _ptr->decrRefCount();
  818.       _ptr = 0;
  819.     }
  820.     _ptr = p;
  821.     return *this;
  822.   }
  823.   
  824.   inline Rope* operator->() const { return _ptr; }
  825.  
  826.   inline operator Rope*() const { return _ptr; }
  827.  
  828.   Rope* _ptr;
  829. };
  830.  
  831. class ropeFactory;
  832.  
  833. class Rope_iterator {
  834. public:
  835.   Rope_iterator(const Anchor *a);
  836.   // Concurrency Control:
  837.   //     MUTEX = a->pd_lock
  838.   // Pre-condition:
  839.   //     Does not hold <MUTEX> on entry
  840.   // Post-condition:
  841.   //     Hold <MUTEX> on exit
  842.  
  843.   Rope_iterator(ropeFactory* rf);
  844.   // Concurrency Control:
  845.   //     MUTEX = rf->anchor()->pd_lock
  846.   // Pre-condition:
  847.   //     Does not hold <MUTEX> on entry
  848.   // Post-condition:
  849.   //     Hold <MUTEX> on exit
  850.  
  851.  
  852.   ~Rope_iterator();
  853.   // Concurrency Control:
  854.   //     MUTEX = a->pd_lock
  855.   // Pre-condition:
  856.   //     Hold <MUTEX> on enter
  857.   // Post-condition:
  858.   //     Does not hold <MUTEX> on enxit
  859.   
  860.   Rope *operator() ();
  861.  
  862. private:
  863.   const Anchor *pd_anchor;
  864.   Rope *pd_r;
  865.   Rope_iterator();
  866. };
  867.  
  868. #endif // __ROPE_H__
  869.